/* Yet Another Experimental Software Renderer
 *
 * Copyright (c) 2010 Pawel "Hery" Dziepak
 */

#include "input_assembler.h"
#include "pipeline.h"

using namespace yaesr;

void default_ia::write_data(std::vector<vertex> &vbo) {
	#pragma omp parallel for shared(vbo)
	for (int i = 0; i < vbo.size(); i++) {
		vbo[i] = vertex_sdr->execute(vbo[i]);
	}

	switch (p_type) {
		case point_list:
			return write_points(vbo);
		case line_strip:
			return write_lines(vbo);
		case triangle_strip:
			return write_triangles(vbo);
		default:
			Warning("Unknown primitives type.");
	}
}

void default_ia::write_points(std::vector<vertex> &vbo) {
	Assert(geometry_sdr != NULL);

	std::vector<point> prims(vbo.size());

	std::vector<line> prims_line;
	std::vector<triangle> prims_triangle;

	#pragma omp parallel for shared(vbo)
	for (int i = 0; i < vbo.size(); i++) {
		point prim;
		prim.vert = vbo[i];

		geometry_sdr->execute(prim, prims, prims_line, prims_triangle);
	}

	next->rasterize_points(prims);
	next->rasterize_lines(prims_line);
	next->rasterize_triangles(prims_triangle);
}

void default_ia::write_lines(std::vector<vertex> &vbo) {
	Assert(geometry_sdr != NULL);

	std::vector<line> prims(vbo.size() - 1);

	std::vector<point> prims_point;
	std::vector<triangle> prims_triangle;

	#pragma omp parallel for shared(vbo)
	for (int i = 0; i < vbo.size(); i++) {
		if (i >= vbo.size() - 1)
			continue;

		line prim;
		prim.vert0 = vbo[i];
		prim.vert1 = vbo[i + 1];

		geometry_sdr->execute(prim, prims_point, prims, prims_triangle);
	}

	next->rasterize_lines(prims);
	next->rasterize_points(prims_point);
	next->rasterize_triangles(prims_triangle);
}

void default_ia::write_triangles(std::vector<vertex> &vbo) {
	Assert(geometry_sdr != NULL);

	std::vector<triangle> basic_prims(vbo.size() - 2);

	#pragma omp parallel for shared(vbo)
	for (int i = 0; i < vbo.size(); i++) {
		if (i >= vbo.size() - 2)
			continue;

		triangle prim;
		prim.vert0 = vbo[i];
		prim.vert1 = vbo[i + 1];
		prim.vert2 = vbo[i + 2];

		tessell->tessellate(prim, basic_prims, hull_sdr->execute(prim));
	}

	std::vector<triangle> prims;
	std::vector<line> prims_line;
	std::vector<point> prims_point;

	#pragma omp parallel for shared(basic_prims, prims, prims_line, prims_point)
	for (int i = 0; i < basic_prims.size(); i++) {
		basic_prims[i].vert0 = domain_sdr->execute(basic_prims[i].vert0.texcoord0, basic_prims[i].vert0);
		basic_prims[i].vert1 = domain_sdr->execute(basic_prims[i].vert1.texcoord0, basic_prims[i].vert1);
		basic_prims[i].vert2 = domain_sdr->execute(basic_prims[i].vert2.texcoord0, basic_prims[i].vert2);

		std::vector<triangle> _prims;
		std::vector<line> _prims_line;
		std::vector<point> _prims_point;

		geometry_sdr->execute(basic_prims[i], _prims_point, _prims_line, _prims);

		#pragma omp critical
		{
			prims.insert(prims.end(), _prims.begin(), _prims.end());
			prims_line.insert(prims_line.end(), _prims_line.begin(), _prims_line.end());
			prims_point.insert(prims_point.end(), _prims_point.begin(), _prims_point.end());
		}
	}

	next->rasterize_lines(prims_line);
	next->rasterize_points(prims_point);

	next->rasterize_triangles(prims);
}